关于python:Cython 0.2:prange意外降低了代码速度 您所在的位置:网站首页 cython python 关于python:Cython 0.2:prange意外降低了代码速度

关于python:Cython 0.2:prange意外降低了代码速度

2023-04-18 21:09| 来源: 网络整理| 查看: 265

在两种情况下考虑优化的cython代码:

123456    for j in xrange(8):         for x in xrange(1, 600):             tmp[j] = 0.0             for y in xrange(1, 800):                 tmp[j] += mag[j, x - 1, y - 1]                 hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]

和:

123456    for j in prange(8):  # < prange used for parallelization with openmp         for x in xrange(1, 600):             tmp[j] = 0.0             for y in xrange(1, 800):                 tmp[j] += mag[j, x - 1, y - 1]                 hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]

在两种情况下,代码都在具有nogil声明的本地函数和具有内存视图和优化布局的numpy数组中。第一种情况的基准运行时间为14.97毫秒,而第二种情况的运行时间为26.64,几乎翻了一番!

除上述情况外,我还有其他功能可以使用prange大大提高多核计算机上的性能,我不知道发生了什么。

关于为什么prange会使代码变慢的任何想法?

FWIW,这是完整的原始代码:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152# cython: boundscheck=False # cython: wraparound=False # cython: nonecheck=False # cython: overflowcheck.fold=True # cython: embedsignature=False # cython: cdivision=True # cython: cdivision_warnings=False # cython: always_allow_keywords=False # cython: profile=False # cython: linetrace=False # cython: infer_types=False # cython: language_level=2 # cython: c_string_type=unicode # cython: c_string_encoding=utf-8 # cython: type_version_tag=True # cython: unraisable_tracebacks=True from __future__ import division import numpy as np cimport numpy as np cimport cython from cython.parallel import prange DTYPE = np.int ctypedef np.int_t DTYPE_t UITYPE = np.uint ctypedef np.uint_t UITYPE_t U8TYPE = np.uint8 ctypedef np.uint8_t U8TYPE_t F32TYPE = np.float32 ctypedef np.float32_t F32TYPE_t F64TYPE = np.float64 ctypedef np.float64_t F64TYPE_t ctypedef Py_ssize_t DSIZE_t cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag,                                 F64TYPE_t [:, :, ::1] hgi_out) nogil:     cdef DSIZE_t m, n, x, y, j, dims = mag.shape[0]     cdef F64TYPE_t [32] tmp     cdef F64TYPE_t val = 0     m, n = mag.shape[1] + 1, mag.shape[2] + 1     for j in prange(dims):         for x in xrange(1, m):             tmp[j] = 0.0             for y in xrange(1, n):                 tmp[j] += mag[j, x - 1, y - 1]                 hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y] def hog_integral_b(mag, hgi_out=None, orientations=8):     if hgi_out is None:         hgi_out = np.zeros((orientations + 1, mag.shape[0] + 1, mag.shape[1] + 1), dtype=F64TYPE)     native_hog_integral_b(mag, hgi_out)     return hgi_out

要测试以上代码,请尝试:

123mg2 = np.random.rand(9, 600, 800).astype(F64TYPE) hg2 = np.zeros((9, mg2.shape[1] + 1, mg2.shape[2] + 1), dtype=F64TYPE) print timeit(lambda:hog_integral_b(mg2, hgi_out=hg2), number=10)

更新:

好的,我仔细查看了setup.py编译器选项:

1234567891011121314151617from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext import numpy as np ext_modules = [Extension("hog_cy", ["hog_cy.pyx"],                          #extra_compile_args = ["-O3","-fopenmp","-fno-strict-aliasing"],                          extra_compile_args = ["-O3","-fopenmp"],                          extra_link_args=["-fopenmp"]                         )] setup (     name = 'performance test app',     cmdclass = {'build_ext': build_ext},     include_dirs = [np.get_include()],     ext_modules = ext_modules, )

选项-fno-strict-aliasing似乎引起了问题,关闭电源后,我没有加速,也没有损失。

相关讨论 你能发表一个完整的例子吗? 我希望问题变得更清楚,发布整个代码。 很抱歉如此,但是您可以添加一个函数来调用形状和dtype正确的样本(随机)数据的hog_integral_b吗? 好,我会做的,给我一些时间 好了,最后用测试代码回答更新 使用您的代码prange在我的计算机上的@ user698585比range更快 @Castro:你在跟我开玩笑!我将在一个单独的程序包中再次检查代码,这可能与编译器选项有关,说到其中,您使用了什么? 在我的时代是一样的 @ Castro,E先生:我在使用mingw和python2.7 32位的Windows7 64位计算机上。我正在使用" -O3"和" -fopenmp"编译器选项,您的选择是什么? @Mr E:也许您没有正确配置openmp,请确保您在其他基准测试中获得了一些提速 @ user698585出于好奇,将OMP_NUM_THREADS环境变量设置为什么? @JoshAdel:设置为2,检查我的更新 groups.google.com/forum/#!forum/cython-users-您可以尝试使用此方法以获得更好/更完整的答案:cython团队会及时做出回应

您正在进行GIL战斗,因为prange不在nogil块内。您的代码中没有并发性,只有多个线程竞争GIL所有权:

123456789101112131415161718cimport cython from cython.parallel cimport prange, parallel cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag,                                 F64TYPE_t [:, :, ::1] hgi_out):     cdef DSIZE_t m, n, j, dims = mag.shape[0]     cdef F64TYPE_t val = 0     m, n = mag.shape[1] + 1, mag.shape[2] + 1     with nogil, parallel():         cdef DSIZE_t x, y         cdef F64TYPE_t tmp         for j in prange(dims):             for x in range(1, m):                 tmp = 0.0                 for y in range(1, n):                     tmp += mag[j, x - 1, y - 1]                     hgi_out[j, x, y] = tmp + hgi_out[j, x - 1, y] 相关讨论 原生函数(native_hog_integral_b)在其签名的末尾带有nogil声明,该声明模式对于其他函数也非常适用(上面的代码未显示)。我在想,也许编译器没有考虑将某些内部变量视为本地线程安全的(例如tmp),但还没有尝试过。 函数的nogil声明不需要释放GIL,也不需要释放GIL,它允许在nogil块内使用该函数。您可以在按住GIL的同时使用nogil函数。除非您键入" with nogil",否则不会释放GIL:

123456789101112131415161718cimport cython from cython.parallel cimport prange, parallel cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag,                                 F64TYPE_t [:, :, ::1] hgi_out):     cdef DSIZE_t m, n, j, dims = mag.shape[0]     cdef F64TYPE_t val = 0     m, n = mag.shape[1] + 1, mag.shape[2] + 1     with nogil, parallel():         cdef DSIZE_t x, y         cdef F64TYPE_t tmp         for j in prange(dims):             for x in range(1, m):                 tmp = 0.0                 for y in range(1, n):                     tmp += mag[j, x - 1, y - 1]                     hgi_out[j, x, y] = tmp + hgi_out[j, x - 1, y]


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有